﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using devtm.Collections;
using devtm.Editor.TypeSelector;
using Mono.Cecil;
using devtm.AutoMapper.TemplateAdd.Models;
using CodeDomHelper.Types;


namespace devtm.AutoMapper.CustomCode.TemplateAdd
{
    public partial class WindowsSelectType : Form
    {

        private TypeSelector _typeSelector;
        private bool includeType;

        public WindowsSelectType()
        {
            InitializeComponent();
            elementHost1.Child = _typeSelector = new TypeSelector();
            _typeSelector.Selected += new EventHandler<AutoMapper.TemplateAdd.SelectedEventArgs>(_typeSelector_Selected);
        }

        void _typeSelector_Selected(object sender, AutoMapper.TemplateAdd.SelectedEventArgs e)
        {
            if (includeType)
                button1.Enabled = e.SelectedItem != null;
            else
                button1.Enabled = e.SelectedNamespace != null;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            this.DialogResult = System.Windows.Forms.DialogResult.OK;
            Close();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
            Close();
        }

        public object SelectedItem
        {
            get
            {
                if (includeType)
                    return _typeSelector.SelectedItem;
                else
                    return _typeSelector.SelectedNamespace;
            }
        }

        internal void SetList(CustomTypeRepository repository, Predicate<TypeDefinition> predicate, string assemblyQualifiedName, bool includeType)
        {

            this.includeType = includeType;

            if (!includeType)
                this.label1.Text = "Select your namespace";
            // change the text label for the namespace search.

            var lst = repository.GetAssemblies().OrderBy(c => c.AssemblyName).ToList();


            TypeExpression t = TypeExpression.Analyse(assemblyQualifiedName);

            TypeDefinition type = repository.GetType(t);

            bool finded = false;

            if (includeType)
            {
                foreach (var item in lst)
                {

                    AssemblyBox b = new AssemblyBox(this, item, repository.Store, predicate, type, includeType);

                    if (b.Count > 0)
                    {
                        _typeSelector.Items.Add(b);

                        if (!finded & b.ShowSelect())
                            finded = true;

                    }

                }
            }
            else
            {
                foreach (var item in lst)
                {

                    AssemblyBox b = new AssemblyBox(this, item, repository.Store, predicate, assemblyQualifiedName, includeType);

                    if (b.Count > 0)
                    {
                        _typeSelector.Items.Add(b);

                        if (!finded & b.ShowSelect())
                            finded = true;

                    }

                }
            }



        }

        private void WindowsSelectType_Load(object sender, EventArgs e)
        {

        }



        /// <summary>
        /// compute the Damerau levenshtein's distance.
        /// </summary>
        /// <param name="string1">The string1.</param>
        /// <param name="string2">The string2.</param>
        /// <returns></returns>
        public static int DamerauLevenshteinDistance(string str1, string str2)
        {

            int lenStr1 = str1.Length;
            int lenStr2 = str2.Length;

            // d is a table with lenStr1+1 rows and lenStr2+1 columns
            int[,] d = new int[lenStr1, lenStr2];

            // i and j are used to iterate over str1 and str2
            int i, j, cost;

            for (i = 0; i < lenStr1; i++)
                d[i, 0] = i;

            for (j = 0; j < lenStr2; i++)
                d[0, j] = j;

            for (i = 1; i <= lenStr1; i++)
                for (j = 1; j <= lenStr2; j++)
                {

                    if (str1[i] == str2[j])
                        cost = 0;
                    else                    
                        cost = 1;

                        int c1 = Math.Min
                        (
                              d[i - 1, j] + 1           // deletion
                            , d[i, j - 1] + 1           // insertion
                        );

                        d[i, j] = Math.Min
                        (
                              c1
                            , d[i - 1, j - 1] + cost    // substitution
                        );

                        if (i > 1 & j > 1 & str1[i] == str2[j - 1] & str1[i - 1] == str2[j])                        
                            d[i, j] = Math.Min(
                                             d[i, j],
                                             d[i - 2, j - 2] + cost   // transposition
                                          );                        
                    

                }

            return d[lenStr1, lenStr2];

        }

    }
}
